use std::error::Error;
use std::io::Write;
use std::ops::Add;
use serde::{Serialize, Deserialize};
use crate::lincni::error::Errors;


#[derive(Debug,Deserialize,Serialize,Default,Clone)]
pub struct PluginInfo {
    #[serde(rename="cniVersion")]
    pub cni_version:String,
    #[serde(rename="supportedVersions")]
    pub support_versions:Vec<String>,
}

impl PluginInfo {
    pub fn all() -> Self  {
        Self::plugin_support(vec![
            "0.1.0".to_string(), "0.2.0".to_string(), "0.3.0".to_string(),
            "0.3.1".to_string(), "0.4.0".to_string(), "1.0.0".to_string()
        ])
    }

    pub fn support_versions(&self) -> Vec<String> {
        self.support_versions.clone()
    }

    pub fn support_versions_string(&self,tag:&str) -> String {
        let mut res = String::new();
        let mut index = 0usize;
        for i in self.support_versions.iter() {
            index += 1;
            res = res.add(i.as_str());
            if index < self.support_versions.len() {
                res = res.add(tag);
            }
        }

        res
    }

    pub fn encode<W>(&self, w: &mut W) -> Result<(), Box<dyn Error>> where W: Write {
        let data = serde_json::to_string(self)?;
        w.write(data.as_bytes())?;

        Ok(())
    }

    pub fn plugin_support(versions:Vec<String>) -> Self {
        if versions.len() <1 {
            panic!("programmer error: you must support at least one version");
        }

        Self{
            cni_version: "1.0.0".to_string(),
            support_versions: versions
        }
    }
}

pub struct PluginDecoder();

impl PluginDecoder {
    pub fn decode(data:Vec<u8>) -> Result<PluginInfo,Box<dyn Error>> {
        let res:PluginInfo = serde_json::from_slice(data.as_slice())?;
        if res.cni_version.is_empty() {
            return Err(Errors::Empty.to_dyn());
        }
        if res.support_versions.len() == 0 {
            if res.cni_version == "0.2.0"  {
                return Ok(PluginInfo::plugin_support(vec!["0.1.0".to_string(),"0.2.0".to_string()]))
            }
            return Err(Errors::FromStr("decoding version info: missing field supportedVersions".to_string()).to_dyn());
        }

        Ok(res)
    }
}
